/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package units;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import utils.Handle;
import java.util.Collections;
import java.util.Set;

/**
 *
 * @author jamie
 */
public class DifferentialExpressionLibrary {

    private TreeMap<MonkeyType, List<DifferentialExpression>> data_monkeyType = new TreeMap<MonkeyType, List<DifferentialExpression>>();
    private TreeMap<Integer, List<DifferentialExpression>> data_timePoints = new TreeMap<Integer, List<DifferentialExpression>>();
    private TreeMap<Integer, List<DifferentialExpression>> data_probe = new TreeMap<Integer, List<DifferentialExpression>>();

    public void populateForMonkeyType(MonkeyType mt, GeneLibrary geneLibrary, Handle handle) {
        String sql = "select distinct probeId, logExp, timePoint, pValue, cellType from differentialexpression where monkeyType='" + mt.name()+"' order by cellType, gId, probeId, timePoint";
        ResultSet rs = handle.runSQLquery(sql);
        if (!data_monkeyType.containsKey(mt)) {
            data_monkeyType.put(mt, new ArrayList<DifferentialExpression>());
        }
        try {
            while (rs.next()) {
                CellType ct = CellType.valueOf(rs.getString("cellType"));
                int probeId = rs.getInt("probeId");
                DifferentialExpression de = new DifferentialExpression(probeId, mt, ct);
                de.setLogExp(rs.getDouble("logExp"));
                de.setTimePoint(rs.getInt("timePoint"));
                de.setpValue(rs.getDouble("pValue"));
                
                data_monkeyType.get(mt).add(de);
                if (!data_timePoints.containsKey(de.getTimePoint())) {
                    data_timePoints.put(de.getTimePoint(), new ArrayList<DifferentialExpression>());
                }
                if (!data_probe.containsKey(de.getProbeId())) {
                    data_probe.put(de.getProbeId(), new ArrayList<DifferentialExpression>());
                }
                data_timePoints.get(de.getTimePoint()).add(de);
                data_probe.get(de.getProbeId()).add(de);
            }
            rs.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public void sort() {
        for (MonkeyType mt : MonkeyType.values()) {
            List<DifferentialExpression> de =  data_monkeyType.get(mt);
            Collections.sort(de);
            
        }
        for (int timePoint : data_timePoints.keySet()) {
            Collections.sort(data_timePoints.get(timePoint));
        }
        for (int probeId: data_probe.keySet()) {
            Collections.sort(data_probe.get(probeId));
        }
    }

    public void clear() {
        data_monkeyType.clear();
        data_timePoints.clear();
    }

    public void populateForAllMonkeyTypes(GeneLibrary library) {
        Handle h = Handle.getConnectedHandle("monkeys");
        for (MonkeyType mt : MonkeyType.values()) {
            populateForMonkeyType(mt, library, h);
        }
        sort();
        h.closeConnection();
    }

    public DifferentialExpression getExpression(int probeId, MonkeyType mt, int timePoint) {
        for (DifferentialExpression de : data_probe.get(probeId)) {
            if (de.getMonkeyType().equals(mt) && timePoint == de.getTimePoint()) {
                return de;
            }
        }
        return null;
    }

    public List<DifferentialExpression> getDifferentialExpression(int probeId) {
        List<DifferentialExpression> exp = new ArrayList<DifferentialExpression>();
        for (DifferentialExpression de : data_probe.get(probeId)) {
            exp.add(de);
        }
        return exp;
    }

    public TreeMap<MonkeyType, DifferentialExpression> getDifferentialExpression(int probeId, int timePoint) {
        TreeMap<MonkeyType, DifferentialExpression> difExpressions = new TreeMap<MonkeyType, DifferentialExpression>();
        for (DifferentialExpression de : data_probe.get(probeId)) {
            if (de.getTimePoint() == timePoint) {
                difExpressions.put(de.getMonkeyType(), de);
            }
        }
        return difExpressions;
    }

    public TreeMap<Integer, DifferentialExpression> getDifferentialExpression(int probeId, MonkeyType mt) {
        TreeMap<Integer, DifferentialExpression> difExpressions = new TreeMap<Integer, DifferentialExpression>();
        if (data_probe.containsKey(probeId)) {
            for (DifferentialExpression de : data_probe.get(probeId)) {
                if (de.getMonkeyType().equals(mt)) {
                    difExpressions.put(de.getTimePoint(), de);
                }
            }
        }
        return difExpressions;
    }

    public List<DifferentialExpression> getDifferentialExpression(int probeId, MonkeyType mt, List<Integer> timePoints) {
        List<DifferentialExpression> difExpressions = new ArrayList<DifferentialExpression>();
        
        if (data_probe.containsKey(probeId)) {
            for (DifferentialExpression de : data_probe.get(probeId)) {
                if (de.getMonkeyType().equals(mt) && timePoints.contains(de.getTimePoint())) {
                    difExpressions.add(de);
                }
            }
        }
        Collections.sort(difExpressions);
        return difExpressions;
    }

    private List<DifferentialExpression> getDifferentialExpression(int probeId, MonkeyType mt, CellType ct, List<Integer> timePoints) {
        List<DifferentialExpression> difExpressions = new ArrayList<DifferentialExpression>();

        if (data_probe.containsKey(probeId)) {
            for (DifferentialExpression de : data_probe.get(probeId)) {
                if (de.getMonkeyType().equals(mt) && timePoints.contains(de.getTimePoint()) && de.getCellType().equals(ct)) {
                    difExpressions.add(de);
                }
            }
        }
        Collections.sort(difExpressions);
        return difExpressions;
    }

    public TreeMap<Integer, List<DifferentialExpression>> getDifferentialExpressedGenes(MonkeyType mt, DiseaseStage ds, double maxP) {
        TreeMap<Integer, List<DifferentialExpression>> de = new TreeMap<Integer, List<DifferentialExpression>>();
        List<Integer> timePoints = getTimePoints(mt, ds);
        for(int probeId : this.getAllProbeIds()){
//            System.out.println("getting expression for gene "+g.getId());
            List<DifferentialExpression> expressions  = getDifferentialExpression(probeId, mt, timePoints);
            if(expressions.size()>0 && hasSignificantExpression(expressions, maxP)){
                if(!de.containsKey(probeId)){
                    de.put(probeId, new ArrayList<DifferentialExpression>());
                }
                de.get(probeId).addAll(expressions);
            }
        }
        return de;
    }

    public TreeMap<Integer, List<DifferentialExpression>> getDifferentialExpressedGenes(MonkeyType mt, CellType ct, DiseaseStage ds, double maxP) {
        TreeMap<Integer, List<DifferentialExpression>> de = new TreeMap<Integer, List<DifferentialExpression>>();
        List<Integer> timePoints = getTimePoints(mt, ds);
        for(int probeId : this.getAllProbeIds()){
//            System.out.println("getting expression for gene "+g.getId());
            List<DifferentialExpression> expressions  = getDifferentialExpression(probeId, mt, ct, timePoints);
            if(expressions.size()>0 && hasSignificantExpression(expressions, maxP)){
                if(!de.containsKey(probeId)){
                    de.put(probeId, new ArrayList<DifferentialExpression>());
                }
                de.get(probeId).addAll(expressions);
            }
        }
        return de;
    }

    public TreeMap<Integer, List<DifferentialExpression>> getDifferentialExpressedGenes(MonkeyType monkeyType, CellType cellType, Integer[] timePoints, double maxP) {
        TreeMap<Integer, List<DifferentialExpression>> de = new TreeMap<Integer, List<DifferentialExpression>>();
        List<Integer> timePointsList = Arrays.asList(timePoints);
        for(int probeId : this.getAllProbeIds()){
//            System.out.println("getting expression for gene "+g.getId());
            List<DifferentialExpression> expressions  = getDifferentialExpression(probeId, monkeyType, cellType, timePointsList);
            if(expressions.size()>0){
                if(hasSignificantExpression(expressions, maxP)){
                    if(!de.containsKey(probeId)){
                        de.put(probeId, new ArrayList<DifferentialExpression>());
                    }
                    de.get(probeId).addAll(expressions);
                }
            }
        }
        return de;
    }


    public List<Integer> getTimePoints(MonkeyType mt, DiseaseStage ds){
        List<Integer> timePoints = new ArrayList<Integer>();
        Handle h = Handle.getConnectedHandle("monkeys");
        String sql = "select distinct timePoint from differentialExpression where monkeyType='"+mt.name()+"' and timePoint>="+ds.getEarliest()+" and timePoint<="+ds.getLatest()+" order by timePoint asc";
        ResultSet rs = h.runSQLquery(sql);
        try {
            while (rs.next()) {
                int tp = rs.getInt("timePoint");
                if(!timePoints.contains(tp)){
                    timePoints.add(tp);
                }
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(DifferentialExpressionLibrary.class.getName()).log(Level.SEVERE, null, ex);
        }
        h.closeConnection();
        return timePoints;
    }

    public Set<Integer> getAllProbeIds() {
        return data_probe.keySet();
    }

    private boolean hasSignificantExpression(List<DifferentialExpression> expressions, double maxP) {
        for(DifferentialExpression de :expressions){
            if(de.getpValue()<maxP){
                return true;
            }
        }
        return false;
    }

    





}
